延庆赛区
延庆赛区的场馆主要有小海坨高山滑雪场、国家雪车雪橇中心、奥运村及媒体中心。国家高山滑雪中心将规划设置两条比赛道、两条训练道和一条技术服务道,冬奥会和冬残奥会的全部高山滑雪项目比赛都将在这里举行。国家雪车雪橇中心将进行雪车、钢架雪车和雪橇三个项目共9个小项的比赛。
小海坨高山滑雪场及其观测站点位置
调用leaflet来显示小海坨高山滑雪场的位置及气象观测站的分布位置.
# define locations
bbox = list(p1 = list(long = 115.7071, lat = 40.47944),
p2 = list(long = 115.8847, lat = 40.58149))
point = list(lon=115.792477, lat=40.535202)
# 观测站点位置
points1 = list(lon=c(115.8136111, 115.8036111, 115.8033333, 115.7977778),
lat=c(40.55861111, 40.55583333, 40.54972222, 40.54111111))
points1_label = c('A1701', 'A1703', 'A1705', 'A1708')
points2 = list(lon=c(115.815, 115.8133333, 115.8069444),
lat=c(40.55194444, 40.54972222, 40.5475))
points2_label = c('A1710', 'A1711', 'A1712')
points3 = list(lon=c(115.7825), lat=c(40.5202777777778))
points3_label = c('A1489')
# show the selected region for olympic region
icon1 <- makeAwesomeIcon(icon= 'flag', markerColor = 'red', iconColor = 'black')
icon2 <- makeAwesomeIcon(icon= 'flag', markerColor = 'green', iconColor = 'black')
icon3 <- makeAwesomeIcon(icon= 'home', markerColor = 'orange', iconColor = 'black')
leaflet(width = "100%") %>%
addProviderTiles(providers$Esri.WorldTopoMap) %>%
addRectangles(
lng1 = bbox$p1$long, lat1 = bbox$p1$lat, lng2 = bbox$p2$long, lat2 = bbox$p2$lat, fillColor="transparent") %>%
addMarkers(
lng=point$lon, lat=point$lat, label="小海坨高山滑雪场") %>%
addAwesomeMarkers(
lng=points1$lon, lat=points1$lat, icon=icon1, label=points1_label) %>%
addAwesomeMarkers(
lng=points2$lon, lat=points2$lat, icon=icon2, label=points2_label) %>%
addAwesomeMarkers(
lng=points3$lon, lat=points3$lat, icon=icon3, label=points3_label) %>%
fitBounds(
lng1 = bbox$p1$long, lat1 = bbox$p1$lat, lng2 = bbox$p2$long, lat2 = bbox$p2$lat,
)
下载地形数据
通过geovis从Mapzen上下载高分辨率的地形数据.
#Get elevation data from Mapzen
datafile <- "data/winter_olympic/xiaohaituo_dem_01.rds"
if(!file.exists(datafile)){
square_km <- 4.5
max_tiles <- 30
dem <- mapzen_dem(point$lat, point$lon, square_km, max_tiles = max_tiles)
saveRDS(dem, datafile)
}
dem <- readRDS(datafile)
Loading required package: raster
Loading required package: sp
# convert to matrix
elmat = raster_to_matrix(dem)
[1] "Dimensions of matrix are: 1032x785."
处理卫星影像数据
通过geovis自带的slippy_overlay函数无法获得超高分辨率卫星影像图像. 目前采用"BIGEMAP地图下载器"下载指定范围内的Google高清影像图, 但未经授权会导致叠加水印. 采用变通办法是直接屏幕截图, 步骤是先选定要下载范围的矩形框, 然后在屏幕上定位矩形两个对角, 然后右键撤销矩形区域, 之后用屏幕截图软件把图像截取下来, 存成png文件. 为了提高图形亮度, 采用图像软件(如snagit editor), 选择颜色调整, 调整Contract和Gamma参数即可.
# Read satellite image
overlay_file <- "data/winter_olympic/xiaohaituo_02_map.png"
overlay_img <- png::readPNG(overlay_file)
显示三维地形数据
zscale = 30
ray_shadow <- ray_shade(elmat, sunaltitude = 20, zscale = zscale, lambert = FALSE)
lamb_shadow <- lamb_shade(elmat, sunaltitude = 20, zscale = zscale)
rgl::clear3d()
elmat %>%
sphere_shade() %>%
add_overlay(overlay_img, alphalayer = 0.95) %>%
add_shadow(ray_shadow, max_darken=0.5) %>%
add_shadow(lamb_shadow, max_darken=0.5) %>%
plot_3d(elmat, zscale = 10,windowsize = c(1500,1000),
theta = -5, phi = 38, zoom = 0.52, fov = 60,
background = "grey40", shadowcolor = "grey10",
soliddepth = -30, shadowdepth = -50)
Sys.sleep(5)
render_snapshot(title_text = "Xiaohaituo Alpine Ski Resort in Yanqing \n2022 Beijing Winter Olympic",
title_size = 50, title_color = "grey90")

for(i in 1:length(points1_label)){
label <- list(text=points1_label[i])
label$pos <- find_image_coordinates(long=points1$lon[i], lat=points1$lat[i], bbox=bbox,
image_width=dim(elmat)[1], image_height=dim(elmat)[2])
render_label(elmat, x = label$pos$x, y = label$pos$y, z = 8500,
zscale = zscale, text = label$text, textsize=2, linewidth = 4, textcolor="magenta", freetype=FALSE)
}
for(i in 1:length(points2_label)){
label <- list(text=points2_label[i])
label$pos <- find_image_coordinates(long=points2$lon[i], lat=points2$lat[i], bbox=bbox,
image_width=dim(elmat)[1], image_height=dim(elmat)[2])
render_label(elmat, x = label$pos$x, y = label$pos$y, z = 8500,
zscale = zscale, text = label$text, textsize=2, linewidth = 4, textcolor="cyan", freetype=FALSE)
}
for(i in 1:length(points3_label)){
label <- list(text=points3_label[i])
label$pos <- find_image_coordinates(long=points3$lon[i], lat=points3$lat[i], bbox=bbox,
image_width=dim(elmat)[1], image_height=dim(elmat)[2])
render_label(elmat, x = label$pos$x, y = label$pos$y, z = 8500,
zscale = zscale, text = label$text, textsize=2, linewidth = 4, textcolor="yellow", freetype=FALSE)
}
render_snapshot(title_text = "Xiaohaituo Alpine Ski Resort in Yanqing \n2022 Beijing Winter Olympic",
title_size = 50, title_color = "grey90")

张家口赛区
在张家口的场馆群中,包括杨树滑雪场、桦林东滑雪胜地、太舞滑雪胜地、云顶滑雪度假村、万龙滑雪场。张家口的滑雪场存雪期长,雪质雪量优良,度风速适宜,非常适宜户外滑雪运动。其将承办越野滑雪、北欧两项、冬季两项、单板滑雪等比赛项目。
古杨树和桦林东两个滑雪场,海拔从1600米延伸到2100多米,最大落差500多米。区域内场地起伏明显、视野开阔明朗,适合开展北欧两项、越野滑雪和冬季两项比赛,并且可利用自然山形建设跳台场地,开展跳台滑雪比赛。
下载崇礼滑雪场地形数据
通过geovis从Mapzen上下载高分辨率的地形数据.
# define center location
point = list(lon=115.444786, lat=40.928771)
#Get elevation data from Mapzen
datafile <- "data/winter_olympic/chongli_dem_01.rds"
if(!file.exists(datafile)){
square_km <- 4
max_tiles <- 50
dem <- mapzen_dem(point$lat, point$lon, square_km, max_tiles = max_tiles)
saveRDS(dem, datafile)
}
dem <- readRDS(datafile)
# convert to matrix
elmat = raster_to_matrix(dem)
[1] "Dimensions of matrix are: 1547x1551."
崇礼滑雪场及其观测站点位置
调用leaflet来显示崇礼滑雪场的位置及气象观测站的分布位置.
# define locations
#bbox = list(p1 = list(long = 115.391294, lat = 40.888247),
# p2 = list(long = 115.501100, lat = 40.967568))
bbox = list(p1 = list(long = xmin(dem), lat = ymin(dem)),
p2 = list(long = xmax(dem), lat = ymax(dem)))
# 观测站点位置
# 云顶滑雪公园
points1 = list(lon=c(115.42, 115.4177778, 115.4102778, 115.4111111),
lat=c(40.95972222, 40.95916667, 40.95583333, 40.95805556))
points1_label = c('B1620', 'B1627', 'B1629', 'B1637')
# 越野滑雪
points2 = list(lon=c(115.4738889, 115.4658333),
lat=c(40.89805556, 40.90166667))
points2_label = c('B1649', 'B1650')
# 冬季两项
points3 = list(lon=c(115.4747222), lat=c(40.90972222))
points3_label = c('B1638')
# 跳台滑雪
points4 = list(lon=c(115.4644444, 115.4652778),
lat=c(40.91, 40.90888889))
points4_label = c('B3158', 'B3159')
# show the selected region for olympic region
icon1 <- makeAwesomeIcon(icon= 'flag', markerColor = 'red', iconColor = 'black')
icon2 <- makeAwesomeIcon(icon= 'flag', markerColor = 'green', iconColor = 'black')
icon3 <- makeAwesomeIcon(icon= 'home', markerColor = 'orange', iconColor = 'black')
icon4 <- makeAwesomeIcon(icon= 'home', markerColor = 'pink', iconColor = 'black')
leaflet(width = "100%") %>%
addProviderTiles(providers$Esri.WorldTopoMap) %>%
addRectangles(
lng1 = bbox$p1$long, lat1 = bbox$p1$lat, lng2 = bbox$p2$long, lat2 = bbox$p2$lat, fillColor="transparent") %>%
addMarkers(
lng=point$lon, lat=point$lat, label="小海坨高山滑雪场") %>%
addAwesomeMarkers(
lng=points1$lon, lat=points1$lat, icon=icon1, label=points1_label) %>%
addAwesomeMarkers(
lng=points2$lon, lat=points2$lat, icon=icon2, label=points2_label) %>%
addAwesomeMarkers(
lng=points3$lon, lat=points3$lat, icon=icon3, label=points3_label) %>%
addAwesomeMarkers(
lng=points4$lon, lat=points4$lat, icon=icon4, label=points4_label) %>%
fitBounds(
lng1 = bbox$p1$long, lat1 = bbox$p1$lat, lng2 = bbox$p2$long, lat2 = bbox$p2$lat,
)
处理卫星影像数据
通过geovis自带的slippy_overlay函数无法获得超高分辨率卫星影像图像. 目前采用"BIGEMAP地图下载器"下载指定范围内的Google高清影像图, 但未经授权会导致叠加水印. 采用变通办法是直接屏幕截图, 步骤是先选定要下载范围的矩形框, 然后在屏幕上定位矩形两个对角, 然后右键撤销矩形区域, 之后用屏幕截图软件把图像截取下来, 存成png文件. 为了提高图形亮度, 采用图像软件(如snagit editor), 选择颜色调整, 调整Contract和Gamma参数即可.
# Read satellite image
overlay_file <- "data/winter_olympic/chongli_02_map.png"
overlay_img <- png::readPNG(overlay_file)
显示三维地形数据
zscale = 30
ray_shadow <- ray_shade(elmat, sunaltitude = 20, zscale = zscale, lambert = FALSE)
lamb_shadow <- lamb_shade(elmat, sunaltitude = 20, zscale = zscale)
rgl::clear3d()
elmat %>%
sphere_shade() %>%
add_overlay(overlay_img, alphalayer = 0.95) %>%
add_shadow(ray_shadow, max_darken=0.5) %>%
add_shadow(lamb_shadow, max_darken=0.5) %>%
plot_3d(elmat, zscale = 5,windowsize = c(1400,1000),
theta = -5, phi = 38, zoom = 0.52, fov = 60,
background = "grey40", shadowcolor = "grey10",
soliddepth = 200, shadowdepth = 100)
Sys.sleep(5)
render_snapshot(title_text = "Chongli Alpine Ski Resort in Zhangjiakou \n2022 Beijing Winter Olympic",
title_size = 50, title_color = "grey90")

z = 13000
for(i in 1:length(points1_label)){
label <- list(text=points1_label[i])
label$pos <- find_image_coordinates(long=points1$lon[i], lat=points1$lat[i], bbox=bbox,
image_width=dim(elmat)[1], image_height=dim(elmat)[2])
render_label(elmat, x = label$pos$x, y = label$pos$y, z = z,
zscale = zscale, text = label$text, textsize=2, linewidth = 4, textcolor="magenta", freetype=FALSE)
}
for(i in 1:length(points2_label)){
label <- list(text=points2_label[i])
label$pos <- find_image_coordinates(long=points2$lon[i], lat=points2$lat[i], bbox=bbox,
image_width=dim(elmat)[1], image_height=dim(elmat)[2])
render_label(elmat, x = label$pos$x, y = label$pos$y, z = z,
zscale = zscale, text = label$text, textsize=2, linewidth = 4, textcolor="cyan", freetype=FALSE)
}
for(i in 1:length(points3_label)){
label <- list(text=points3_label[i])
label$pos <- find_image_coordinates(long=points3$lon[i], lat=points3$lat[i], bbox=bbox,
image_width=dim(elmat)[1], image_height=dim(elmat)[2])
render_label(elmat, x = label$pos$x, y = label$pos$y, z = z,
zscale = zscale, text = label$text, textsize=2, linewidth = 4, textcolor="yellow", freetype=FALSE)
}
for(i in 1:length(points4_label)){
label <- list(text=points4_label[i])
label$pos <- find_image_coordinates(long=points4$lon[i], lat=points4$lat[i], bbox=bbox,
image_width=dim(elmat)[1], image_height=dim(elmat)[2])
render_label(elmat, x = label$pos$x, y = label$pos$y, z = z,
zscale = zscale, text = label$text, textsize=2, linewidth = 4, textcolor="green", freetype=FALSE)
}
render_snapshot(title_text = "Chongli Alpine Ski Resort in Zhangjiakou \n2022 Beijing Winter Olympic",
title_size = 50, title_color = "grey90")

LS0tDQp0aXRsZTogIjIwMjLlubTlhqzlraPlpaXov5DkvJrmr5TotZvlnLrlnLDliIbmnpAiDQpvdXRwdXQ6DQogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBwZGZfZG9jdW1lbnQ6DQogICAgaW5jbHVkZXM6DQogICAgICBoZWFkZXItaW5jbHVkZXM6IFx1c2VwYWNrYWdle3hlQ0pLfQ0KICAgIGtlZXBfdGV4OiB5ZXMNCiAgICBsYXRleF9lbmdpbmU6IHhlbGF0ZXgNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCkNKS21haW5mb250OiBNaWNyb3NvZnQgWWFIZWkNCi0tLQ0KDQojIyDmpoLlhrUNCiAgICAyMDIy5bm0MuaciDTml6Xoh7My5pyIMjDml6XvvIznrKwyNOWxiuWGrOWlpeS8muWwhuWcqOWMl+S6rOW4guWSjOW8oOWutuWPo+W4guiBlOWQiOS4vuihjOOAguWMl+S6rOWwhuaJv+WKnuaJgOacieWGsOS4iumhueebru+8jOW7tuW6huWSjOW8oOWutuWPo+WwhuaJv+WKnuaJgOacieeahOmbquS4iumhueebruOAgg0KDQojIyMgU2V0dXANCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkobGVhZmxldCkNCmxpYnJhcnkocmFzdGVyKQ0KbGlicmFyeShzcCkNCmxpYnJhcnkocmF5c2hhZGVyKQ0KbGlicmFyeShnZW92aXopDQpsaWJyYXJ5KG5tY01ldElPKQ0KYGBgDQoNCg0KIyMg5bu25bqG6LWb5Yy6DQogICAg5bu25bqG6LWb5Yy655qE5Zy66aaG5Li76KaB5pyJ5bCP5rW35Z2o6auY5bGx5ruR6Zuq5Zy644CB5Zu95a626Zuq6L2m6Zuq5qmH5Lit5b+D44CB5aWl6L+Q5p2R5Y+K5aqS5L2T5Lit5b+D44CC5Zu95a626auY5bGx5ruR6Zuq5Lit5b+D5bCG6KeE5YiS6K6+572u5Lik5p2h5q+U6LWb6YGT44CB5Lik5p2h6K6t57uD6YGT5ZKM5LiA5p2h5oqA5pyv5pyN5Yqh6YGT77yM5Yas5aWl5Lya5ZKM5Yas5q6L5aWl5Lya55qE5YWo6YOo6auY5bGx5ruR6Zuq6aG555uu5q+U6LWb6YO95bCG5Zyo6L+Z6YeM5Li+6KGM44CC5Zu95a626Zuq6L2m6Zuq5qmH5Lit5b+D5bCG6L+b6KGM6Zuq6L2m44CB6ZKi5p626Zuq6L2m5ZKM6Zuq5qmH5LiJ5Liq6aG555uu5YWxOeS4quWwj+mhueeahOavlOi1m+OAgg0KDQohW+Wwj+a1t+WdqOmrmOWxsea7kembquWcul0oLi9kYXRhL3dpbnRlcl9vbHltcGljL+W7tuW6hui1m+WMujAxLmpwZykNCg0KIyMjIOWwj+a1t+WdqOmrmOWxsea7kembquWcuuWPiuWFtuingua1i+ermeeCueS9jee9rg0KICDosIPnlKhsZWFmbGV05p2l5pi+56S65bCP5rW35Z2o6auY5bGx5ruR6Zuq5Zy655qE5L2N572u5Y+K5rCU6LGh6KeC5rWL56uZ55qE5YiG5biD5L2N572uLg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiMgZGVmaW5lIGxvY2F0aW9ucw0KYmJveCA9IGxpc3QocDEgPSBsaXN0KGxvbmcgPSAxMTUuNzA3MSwgbGF0ID0gNDAuNDc5NDQpLA0KICAgICAgICAgICAgcDIgPSBsaXN0KGxvbmcgPSAxMTUuODg0NywgbGF0ID0gNDAuNTgxNDkpKQ0KcG9pbnQgPSBsaXN0KGxvbj0xMTUuNzkyNDc3LCBsYXQ9NDAuNTM1MjAyKQ0KDQojIOingua1i+ermeeCueS9jee9rg0KcG9pbnRzMSA9IGxpc3QobG9uPWMoMTE1LjgxMzYxMTEsIDExNS44MDM2MTExLCAxMTUuODAzMzMzMywgMTE1Ljc5Nzc3NzgpLA0KICAgICAgICAgICAgICAgbGF0PWMoNDAuNTU4NjExMTEsIDQwLjU1NTgzMzMzLCA0MC41NDk3MjIyMiwgNDAuNTQxMTExMTEpKQ0KcG9pbnRzMV9sYWJlbCA9IGMoJ0ExNzAxJywgJ0ExNzAzJywgJ0ExNzA1JywgJ0ExNzA4JykNCnBvaW50czIgPSBsaXN0KGxvbj1jKDExNS44MTUsIDExNS44MTMzMzMzLCAxMTUuODA2OTQ0NCksDQogICAgICAgICAgICAgICBsYXQ9Yyg0MC41NTE5NDQ0NCwgNDAuNTQ5NzIyMjIsIDQwLjU0NzUpKQ0KcG9pbnRzMl9sYWJlbCA9IGMoJ0ExNzEwJywgJ0ExNzExJywgJ0ExNzEyJykNCnBvaW50czMgPSBsaXN0KGxvbj1jKDExNS43ODI1KSwgbGF0PWMoNDAuNTIwMjc3Nzc3Nzc3OCkpDQpwb2ludHMzX2xhYmVsID0gYygnQTE0ODknKQ0KDQojIHNob3cgdGhlIHNlbGVjdGVkIHJlZ2lvbiBmb3Igb2x5bXBpYyByZWdpb24NCmljb24xIDwtIG1ha2VBd2Vzb21lSWNvbihpY29uPSAnZmxhZycsIG1hcmtlckNvbG9yID0gJ3JlZCcsIGljb25Db2xvciA9ICdibGFjaycpDQppY29uMiA8LSBtYWtlQXdlc29tZUljb24oaWNvbj0gJ2ZsYWcnLCBtYXJrZXJDb2xvciA9ICdncmVlbicsIGljb25Db2xvciA9ICdibGFjaycpDQppY29uMyA8LSBtYWtlQXdlc29tZUljb24oaWNvbj0gJ2hvbWUnLCBtYXJrZXJDb2xvciA9ICdvcmFuZ2UnLCBpY29uQ29sb3IgPSAnYmxhY2snKQ0KbGVhZmxldCh3aWR0aCA9ICIxMDAlIikgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJEVzcmkuV29ybGRUb3BvTWFwKSAlPiUgDQogIGFkZFJlY3RhbmdsZXMoDQogICAgbG5nMSA9IGJib3gkcDEkbG9uZywgbGF0MSA9IGJib3gkcDEkbGF0LCBsbmcyID0gYmJveCRwMiRsb25nLCBsYXQyID0gYmJveCRwMiRsYXQsIGZpbGxDb2xvcj0idHJhbnNwYXJlbnQiKSAlPiUNCiAgYWRkTWFya2VycygNCiAgICBsbmc9cG9pbnQkbG9uLCBsYXQ9cG9pbnQkbGF0LCBsYWJlbD0i5bCP5rW35Z2o6auY5bGx5ruR6Zuq5Zy6IikgJT4lDQogIGFkZEF3ZXNvbWVNYXJrZXJzKA0KICAgIGxuZz1wb2ludHMxJGxvbiwgbGF0PXBvaW50czEkbGF0LCBpY29uPWljb24xLCBsYWJlbD1wb2ludHMxX2xhYmVsKSAlPiUNCiAgYWRkQXdlc29tZU1hcmtlcnMoDQogICAgbG5nPXBvaW50czIkbG9uLCBsYXQ9cG9pbnRzMiRsYXQsIGljb249aWNvbjIsIGxhYmVsPXBvaW50czJfbGFiZWwpICU+JQ0KICBhZGRBd2Vzb21lTWFya2VycygNCiAgICBsbmc9cG9pbnRzMyRsb24sIGxhdD1wb2ludHMzJGxhdCwgaWNvbj1pY29uMywgbGFiZWw9cG9pbnRzM19sYWJlbCkgJT4lDQogIGZpdEJvdW5kcygNCiAgICBsbmcxID0gYmJveCRwMSRsb25nLCBsYXQxID0gYmJveCRwMSRsYXQsIGxuZzIgPSBiYm94JHAyJGxvbmcsIGxhdDIgPSBiYm94JHAyJGxhdCwNCiAgKQ0KYGBgDQoNCiMjIyDkuIvovb3lnLDlvaLmlbDmja4NCiAgICDpgJrov4dnZW92aXPku45NYXB6ZW7kuIrkuIvovb3pq5jliIbovqjnjofnmoTlnLDlvaLmlbDmja4uDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KI0dldCBlbGV2YXRpb24gZGF0YSBmcm9tIE1hcHplbg0KZGF0YWZpbGUgPC0gImRhdGEvd2ludGVyX29seW1waWMveGlhb2hhaXR1b19kZW1fMDEucmRzIg0KaWYoIWZpbGUuZXhpc3RzKGRhdGFmaWxlKSl7DQogIHNxdWFyZV9rbSA8LSA0LjUNCiAgbWF4X3RpbGVzIDwtIDMwDQogIGRlbSA8LSBtYXB6ZW5fZGVtKHBvaW50JGxhdCwgcG9pbnQkbG9uLCBzcXVhcmVfa20sIG1heF90aWxlcyA9IG1heF90aWxlcykNCiAgc2F2ZVJEUyhkZW0sIGRhdGFmaWxlKQ0KfQ0KZGVtIDwtIHJlYWRSRFMoZGF0YWZpbGUpDQoNCiMgY29udmVydCB0byBtYXRyaXgNCmVsbWF0ID0gcmFzdGVyX3RvX21hdHJpeChkZW0pDQpgYGANCg0KIyMjIOWkhOeQhuWNq+aYn+W9seWDj+aVsOaNrg0KICAgIOmAmui/h2dlb3Zpc+iHquW4pueahHNsaXBweV9vdmVybGF55Ye95pWw5peg5rOV6I635b6X6LaF6auY5YiG6L6o546H5Y2r5pif5b2x5YOP5Zu+5YOPLiDnm67liY3ph4fnlKgiQklHRU1BUOWcsOWbvuS4i+i9veWZqCLkuIvovb3mjIflrprojIPlm7TlhoXnmoRHb29nbGXpq5jmuIXlvbHlg4/lm74sIOS9huacque7j+aOiOadg+S8muWvvOiHtOWPoOWKoOawtOWNsC4g6YeH55So5Y+Y6YCa5Yqe5rOV5piv55u05o6l5bGP5bmV5oiq5Zu+LCDmraXpqqTmmK/lhYjpgInlrpropoHkuIvovb3ojIPlm7TnmoTnn6nlvaLmoYYsIOeEtuWQjuWcqOWxj+W5leS4iuWumuS9jeefqeW9ouS4pOS4quWvueinkiwg54S25ZCO5Y+z6ZSu5pKk6ZSA55+p5b2i5Yy65Z+fLCDkuYvlkI7nlKjlsY/luZXmiKrlm77ova/ku7bmiorlm77lg4/miKrlj5bkuIvmnaUsIOWtmOaIkHBuZ+aWh+S7ti4g5Li65LqG5o+Q6auY5Zu+5b2i5Lqu5bqmLCDph4fnlKjlm77lg4/ova/ku7Yo5aaCc25hZ2l0IGVkaXRvciksIOmAieaLqeminOiJsuiwg+aVtCwg6LCD5pW0Q29udHJhY3TlkoxHYW1tYeWPguaVsOWNs+WPry4NCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiMgUmVhZCBzYXRlbGxpdGUgaW1hZ2UNCm92ZXJsYXlfZmlsZSA8LSAiZGF0YS93aW50ZXJfb2x5bXBpYy94aWFvaGFpdHVvXzAyX21hcC5wbmciDQpvdmVybGF5X2ltZyA8LSBwbmc6OnJlYWRQTkcob3ZlcmxheV9maWxlKQ0KYGBgDQoNCiMjIyDmmL7npLrkuInnu7TlnLDlvaLmlbDmja4NCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnpzY2FsZSA9IDMwDQpyYXlfc2hhZG93IDwtIHJheV9zaGFkZShlbG1hdCwgc3VuYWx0aXR1ZGUgPSAyMCwgenNjYWxlID0genNjYWxlLCBsYW1iZXJ0ID0gRkFMU0UpDQpsYW1iX3NoYWRvdyA8LSBsYW1iX3NoYWRlKGVsbWF0LCBzdW5hbHRpdHVkZSA9IDIwLCB6c2NhbGUgPSB6c2NhbGUpDQpgYGANCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTE1fQ0KcmdsOjpjbGVhcjNkKCkNCmVsbWF0ICU+JQ0KICBzcGhlcmVfc2hhZGUoKSAlPiUNCiAgYWRkX292ZXJsYXkob3ZlcmxheV9pbWcsIGFscGhhbGF5ZXIgPSAwLjk1KSAlPiUNCiAgYWRkX3NoYWRvdyhyYXlfc2hhZG93LCBtYXhfZGFya2VuPTAuNSkgJT4lDQogIGFkZF9zaGFkb3cobGFtYl9zaGFkb3csIG1heF9kYXJrZW49MC41KSAlPiUNCiAgcGxvdF8zZChlbG1hdCwgenNjYWxlID0gMTAsd2luZG93c2l6ZSA9IGMoMTUwMCwxMDAwKSwgDQogICAgICAgICAgdGhldGEgPSAtNSwgcGhpID0gMzgsIHpvb20gPSAwLjUyLCBmb3YgPSA2MCwNCiAgICAgICAgICBiYWNrZ3JvdW5kID0gImdyZXk0MCIsIHNoYWRvd2NvbG9yID0gImdyZXkxMCIsIA0KICAgICAgICAgIHNvbGlkZGVwdGggPSAtMzAsIHNoYWRvd2RlcHRoID0gLTUwKQ0KU3lzLnNsZWVwKDUpDQpyZW5kZXJfc25hcHNob3QodGl0bGVfdGV4dCA9ICJYaWFvaGFpdHVvIEFscGluZSBTa2kgUmVzb3J0IGluIFlhbnFpbmcgXG4yMDIyIEJlaWppbmcgV2ludGVyIE9seW1waWMiLA0KICAgICAgICAgICAgICAgIHRpdGxlX3NpemUgPSA1MCwgdGl0bGVfY29sb3IgPSAiZ3JleTkwIikNCmBgYA0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTE1fQ0KDQpmb3IoaSBpbiAxOmxlbmd0aChwb2ludHMxX2xhYmVsKSl7DQogIGxhYmVsIDwtIGxpc3QodGV4dD1wb2ludHMxX2xhYmVsW2ldKQ0KICBsYWJlbCRwb3MgPC0gZmluZF9pbWFnZV9jb29yZGluYXRlcyhsb25nPXBvaW50czEkbG9uW2ldLCBsYXQ9cG9pbnRzMSRsYXRbaV0sIGJib3g9YmJveCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltYWdlX3dpZHRoPWRpbShlbG1hdClbMV0sIGltYWdlX2hlaWdodD1kaW0oZWxtYXQpWzJdKQ0KICByZW5kZXJfbGFiZWwoZWxtYXQsIHggPSBsYWJlbCRwb3MkeCwgeSA9IGxhYmVsJHBvcyR5LCB6ID0gODUwMCwNCiAgICAgICAgICAgICAgIHpzY2FsZSA9IHpzY2FsZSwgdGV4dCA9IGxhYmVsJHRleHQsIHRleHRzaXplPTIsIGxpbmV3aWR0aCA9IDQsIHRleHRjb2xvcj0ibWFnZW50YSIsIGZyZWV0eXBlPUZBTFNFKQ0KfQ0KDQpmb3IoaSBpbiAxOmxlbmd0aChwb2ludHMyX2xhYmVsKSl7DQogIGxhYmVsIDwtIGxpc3QodGV4dD1wb2ludHMyX2xhYmVsW2ldKQ0KICBsYWJlbCRwb3MgPC0gZmluZF9pbWFnZV9jb29yZGluYXRlcyhsb25nPXBvaW50czIkbG9uW2ldLCBsYXQ9cG9pbnRzMiRsYXRbaV0sIGJib3g9YmJveCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltYWdlX3dpZHRoPWRpbShlbG1hdClbMV0sIGltYWdlX2hlaWdodD1kaW0oZWxtYXQpWzJdKQ0KICByZW5kZXJfbGFiZWwoZWxtYXQsIHggPSBsYWJlbCRwb3MkeCwgeSA9IGxhYmVsJHBvcyR5LCB6ID0gODUwMCwNCiAgICAgICAgICAgICAgIHpzY2FsZSA9IHpzY2FsZSwgdGV4dCA9IGxhYmVsJHRleHQsIHRleHRzaXplPTIsIGxpbmV3aWR0aCA9IDQsIHRleHRjb2xvcj0iY3lhbiIsIGZyZWV0eXBlPUZBTFNFKQ0KfQ0KDQpmb3IoaSBpbiAxOmxlbmd0aChwb2ludHMzX2xhYmVsKSl7DQogIGxhYmVsIDwtIGxpc3QodGV4dD1wb2ludHMzX2xhYmVsW2ldKQ0KICBsYWJlbCRwb3MgPC0gZmluZF9pbWFnZV9jb29yZGluYXRlcyhsb25nPXBvaW50czMkbG9uW2ldLCBsYXQ9cG9pbnRzMyRsYXRbaV0sIGJib3g9YmJveCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltYWdlX3dpZHRoPWRpbShlbG1hdClbMV0sIGltYWdlX2hlaWdodD1kaW0oZWxtYXQpWzJdKQ0KICByZW5kZXJfbGFiZWwoZWxtYXQsIHggPSBsYWJlbCRwb3MkeCwgeSA9IGxhYmVsJHBvcyR5LCB6ID0gODUwMCwNCiAgICAgICAgICAgICAgIHpzY2FsZSA9IHpzY2FsZSwgdGV4dCA9IGxhYmVsJHRleHQsIHRleHRzaXplPTIsIGxpbmV3aWR0aCA9IDQsIHRleHRjb2xvcj0ieWVsbG93IiwgZnJlZXR5cGU9RkFMU0UpDQp9DQoNCnJlbmRlcl9zbmFwc2hvdCh0aXRsZV90ZXh0ID0gIlhpYW9oYWl0dW8gQWxwaW5lIFNraSBSZXNvcnQgaW4gWWFucWluZyBcbjIwMjIgQmVpamluZyBXaW50ZXIgT2x5bXBpYyIsDQogICAgICAgICAgICAgICAgdGl0bGVfc2l6ZSA9IDUwLCB0aXRsZV9jb2xvciA9ICJncmV5OTAiKQ0KYGBgDQoNCiMjIOW8oOWutuWPo+i1m+WMug0KICAgIOWcqOW8oOWutuWPo+eahOWcuummhue+pOS4re+8jOWMheaLrOadqOagkea7kembquWcuuOAgeahpuael+S4nOa7kembquiDnOWcsOOAgeWkquiInua7kembquiDnOWcsOOAgeS6kemhtua7kembquW6puWBh+adkeOAgeS4h+m+mea7kembquWcuuOAguW8oOWutuWPo+eahOa7kembquWcuuWtmOmbquacn+mVv++8jOmbqui0qOmbqumHj+S8mOiJr++8jOW6pumjjumAn+mAguWunO+8jOmdnuW4uOmAguWunOaIt+Wklua7kembqui/kOWKqOOAguWFtuWwhuaJv+WKnui2iumHjua7kembquOAgeWMl+asp+S4pOmhueOAgeWGrOWto+S4pOmhueOAgeWNleadv+a7kembquetieavlOi1m+mhueebruOAgg0KICAgIOWPpOadqOagkeWSjOahpuael+S4nOS4pOS4qua7kembquWcuu+8jOa1t+aLlOS7jjE2MDDnsbPlu7bkvLjliLAyMTAw5aSa57Gz77yM5pyA5aSn6JC95beuNTAw5aSa57Gz44CC5Yy65Z+f5YaF5Zy65Zyw6LW35LyP5piO5pi+44CB6KeG6YeO5byA6ZiU5piO5pyX77yM6YCC5ZCI5byA5bGV5YyX5qyn5Lik6aG544CB6LaK6YeO5ruR6Zuq5ZKM5Yas5a2j5Lik6aG55q+U6LWb77yM5bm25LiU5Y+v5Yip55So6Ieq54S25bGx5b2i5bu66K6+6Lez5Y+w5Zy65Zyw77yM5byA5bGV6Lez5Y+w5ruR6Zuq5q+U6LWb44CCDQogICAgDQohW+W8oOWutuWPo+i1m+WMul0oLi9kYXRhL3dpbnRlcl9vbHltcGljL+W0h+ekvOi1m+WMui5qcGcpDQoNCiMjIyDkuIvovb3ltIfnpLzmu5Hpm6rlnLrlnLDlvaLmlbDmja4NCiAgICDpgJrov4dnZW92aXPku45NYXB6ZW7kuIrkuIvovb3pq5jliIbovqjnjofnmoTlnLDlvaLmlbDmja4uDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KIyBkZWZpbmUgY2VudGVyIGxvY2F0aW9uDQpwb2ludCA9IGxpc3QobG9uPTExNS40NDQ3ODYsIGxhdD00MC45Mjg3NzEpDQoNCiNHZXQgZWxldmF0aW9uIGRhdGEgZnJvbSBNYXB6ZW4NCmRhdGFmaWxlIDwtICJkYXRhL3dpbnRlcl9vbHltcGljL2Nob25nbGlfZGVtXzAxLnJkcyINCmlmKCFmaWxlLmV4aXN0cyhkYXRhZmlsZSkpew0KICBzcXVhcmVfa20gPC0gNA0KICBtYXhfdGlsZXMgPC0gNTANCiAgZGVtIDwtIG1hcHplbl9kZW0ocG9pbnQkbGF0LCBwb2ludCRsb24sIHNxdWFyZV9rbSwgbWF4X3RpbGVzID0gbWF4X3RpbGVzKQ0KICBzYXZlUkRTKGRlbSwgZGF0YWZpbGUpDQp9DQpkZW0gPC0gcmVhZFJEUyhkYXRhZmlsZSkNCg0KIyBjb252ZXJ0IHRvIG1hdHJpeA0KZWxtYXQgPSByYXN0ZXJfdG9fbWF0cml4KGRlbSkNCmBgYA0KDQojIyMg5bSH56S85ruR6Zuq5Zy65Y+K5YW26KeC5rWL56uZ54K55L2N572uDQogIOiwg+eUqGxlYWZsZXTmnaXmmL7npLrltIfnpLzmu5Hpm6rlnLrnmoTkvY3nva7lj4rmsJTosaHop4LmtYvnq5nnmoTliIbluIPkvY3nva4uDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KIyBkZWZpbmUgbG9jYXRpb25zDQojYmJveCA9IGxpc3QocDEgPSBsaXN0KGxvbmcgPSAxMTUuMzkxMjk0LCBsYXQgPSA0MC44ODgyNDcpLA0KIyAgICAgICAgICAgIHAyID0gbGlzdChsb25nID0gMTE1LjUwMTEwMCwgbGF0ID0gNDAuOTY3NTY4KSkNCmJib3ggPSBsaXN0KHAxID0gbGlzdChsb25nID0geG1pbihkZW0pLCBsYXQgPSB5bWluKGRlbSkpLA0KICAgICAgICAgICAgcDIgPSBsaXN0KGxvbmcgPSB4bWF4KGRlbSksIGxhdCA9IHltYXgoZGVtKSkpDQoNCiMg6KeC5rWL56uZ54K55L2N572uDQojIOS6kemhtua7kembquWFrOWbrQ0KcG9pbnRzMSA9IGxpc3QobG9uPWMoMTE1LjQyLCAxMTUuNDE3Nzc3OCwgMTE1LjQxMDI3NzgsIDExNS40MTExMTExKSwNCiAgICAgICAgICAgICAgIGxhdD1jKDQwLjk1OTcyMjIyLCA0MC45NTkxNjY2NywgNDAuOTU1ODMzMzMsIDQwLjk1ODA1NTU2KSkNCnBvaW50czFfbGFiZWwgPSBjKCdCMTYyMCcsICdCMTYyNycsICdCMTYyOScsICdCMTYzNycpDQojIOi2iumHjua7kembqg0KcG9pbnRzMiA9IGxpc3QobG9uPWMoMTE1LjQ3Mzg4ODksIDExNS40NjU4MzMzKSwNCiAgICAgICAgICAgICAgIGxhdD1jKDQwLjg5ODA1NTU2LCA0MC45MDE2NjY2NykpDQpwb2ludHMyX2xhYmVsID0gYygnQjE2NDknLCAnQjE2NTAnKQ0KIyDlhqzlraPkuKTpobkNCnBvaW50czMgPSBsaXN0KGxvbj1jKDExNS40NzQ3MjIyKSwgbGF0PWMoNDAuOTA5NzIyMjIpKQ0KcG9pbnRzM19sYWJlbCA9IGMoJ0IxNjM4JykNCiMg6Lez5Y+w5ruR6ZuqDQpwb2ludHM0ID0gbGlzdChsb249YygxMTUuNDY0NDQ0NCwgMTE1LjQ2NTI3NzgpLA0KICAgICAgICAgICAgICAgbGF0PWMoNDAuOTEsIDQwLjkwODg4ODg5KSkNCnBvaW50czRfbGFiZWwgPSBjKCdCMzE1OCcsICdCMzE1OScpDQoNCiMgc2hvdyB0aGUgc2VsZWN0ZWQgcmVnaW9uIGZvciBvbHltcGljIHJlZ2lvbg0KaWNvbjEgPC0gbWFrZUF3ZXNvbWVJY29uKGljb249ICdmbGFnJywgbWFya2VyQ29sb3IgPSAncmVkJywgaWNvbkNvbG9yID0gJ2JsYWNrJykNCmljb24yIDwtIG1ha2VBd2Vzb21lSWNvbihpY29uPSAnZmxhZycsIG1hcmtlckNvbG9yID0gJ2dyZWVuJywgaWNvbkNvbG9yID0gJ2JsYWNrJykNCmljb24zIDwtIG1ha2VBd2Vzb21lSWNvbihpY29uPSAnaG9tZScsIG1hcmtlckNvbG9yID0gJ29yYW5nZScsIGljb25Db2xvciA9ICdibGFjaycpDQppY29uNCA8LSBtYWtlQXdlc29tZUljb24oaWNvbj0gJ2hvbWUnLCBtYXJrZXJDb2xvciA9ICdwaW5rJywgaWNvbkNvbG9yID0gJ2JsYWNrJykNCmxlYWZsZXQod2lkdGggPSAiMTAwJSIpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRFc3JpLldvcmxkVG9wb01hcCkgJT4lIA0KICBhZGRSZWN0YW5nbGVzKA0KICAgIGxuZzEgPSBiYm94JHAxJGxvbmcsIGxhdDEgPSBiYm94JHAxJGxhdCwgbG5nMiA9IGJib3gkcDIkbG9uZywgbGF0MiA9IGJib3gkcDIkbGF0LCBmaWxsQ29sb3I9InRyYW5zcGFyZW50IikgJT4lDQogIGFkZE1hcmtlcnMoDQogICAgbG5nPXBvaW50JGxvbiwgbGF0PXBvaW50JGxhdCwgbGFiZWw9IuWwj+a1t+WdqOmrmOWxsea7kembquWcuiIpICU+JQ0KICBhZGRBd2Vzb21lTWFya2VycygNCiAgICBsbmc9cG9pbnRzMSRsb24sIGxhdD1wb2ludHMxJGxhdCwgaWNvbj1pY29uMSwgbGFiZWw9cG9pbnRzMV9sYWJlbCkgJT4lDQogIGFkZEF3ZXNvbWVNYXJrZXJzKA0KICAgIGxuZz1wb2ludHMyJGxvbiwgbGF0PXBvaW50czIkbGF0LCBpY29uPWljb24yLCBsYWJlbD1wb2ludHMyX2xhYmVsKSAlPiUNCiAgYWRkQXdlc29tZU1hcmtlcnMoDQogICAgbG5nPXBvaW50czMkbG9uLCBsYXQ9cG9pbnRzMyRsYXQsIGljb249aWNvbjMsIGxhYmVsPXBvaW50czNfbGFiZWwpICU+JQ0KICBhZGRBd2Vzb21lTWFya2VycygNCiAgICBsbmc9cG9pbnRzNCRsb24sIGxhdD1wb2ludHM0JGxhdCwgaWNvbj1pY29uNCwgbGFiZWw9cG9pbnRzNF9sYWJlbCkgJT4lDQogIGZpdEJvdW5kcygNCiAgICBsbmcxID0gYmJveCRwMSRsb25nLCBsYXQxID0gYmJveCRwMSRsYXQsIGxuZzIgPSBiYm94JHAyJGxvbmcsIGxhdDIgPSBiYm94JHAyJGxhdCwNCiAgKQ0KYGBgDQoNCiMjIyDlpITnkIbljavmmJ/lvbHlg4/mlbDmja4NCiAgICDpgJrov4dnZW92aXPoh6rluKbnmoRzbGlwcHlfb3ZlcmxheeWHveaVsOaXoOazleiOt+W+l+i2hemrmOWIhui+qOeOh+WNq+aYn+W9seWDj+WbvuWDjy4g55uu5YmN6YeH55SoIkJJR0VNQVDlnLDlm77kuIvovb3lmagi5LiL6L295oyH5a6a6IyD5Zu05YaF55qER29vZ2xl6auY5riF5b2x5YOP5Zu+LCDkvYbmnKrnu4/mjojmnYPkvJrlr7zoh7Tlj6DliqDmsLTljbAuIOmHh+eUqOWPmOmAmuWKnuazleaYr+ebtOaOpeWxj+W5leaIquWbviwg5q2l6aqk5piv5YWI6YCJ5a6a6KaB5LiL6L296IyD5Zu055qE55+p5b2i5qGGLCDnhLblkI7lnKjlsY/luZXkuIrlrprkvY3nn6nlvaLkuKTkuKrlr7nop5IsIOeEtuWQjuWPs+mUruaSpOmUgOefqeW9ouWMuuWfnywg5LmL5ZCO55So5bGP5bmV5oiq5Zu+6L2v5Lu25oqK5Zu+5YOP5oiq5Y+W5LiL5p2lLCDlrZjmiJBwbmfmlofku7YuIOS4uuS6huaPkOmrmOWbvuW9ouS6ruW6piwg6YeH55So5Zu+5YOP6L2v5Lu2KOWmgnNuYWdpdCBlZGl0b3IpLCDpgInmi6npopzoibLosIPmlbQsIOiwg+aVtENvbnRyYWN05ZKMR2FtbWHlj4LmlbDljbPlj68uDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojIFJlYWQgc2F0ZWxsaXRlIGltYWdlDQpvdmVybGF5X2ZpbGUgPC0gImRhdGEvd2ludGVyX29seW1waWMvY2hvbmdsaV8wMl9tYXAucG5nIg0Kb3ZlcmxheV9pbWcgPC0gcG5nOjpyZWFkUE5HKG92ZXJsYXlfZmlsZSkNCmBgYA0KDQojIyMg5pi+56S65LiJ57u05Zyw5b2i5pWw5o2uDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQp6c2NhbGUgPSAzMA0KcmF5X3NoYWRvdyA8LSByYXlfc2hhZGUoZWxtYXQsIHN1bmFsdGl0dWRlID0gMjAsIHpzY2FsZSA9IHpzY2FsZSwgbGFtYmVydCA9IEZBTFNFKQ0KbGFtYl9zaGFkb3cgPC0gbGFtYl9zaGFkZShlbG1hdCwgc3VuYWx0aXR1ZGUgPSAyMCwgenNjYWxlID0genNjYWxlKQ0KYGBgDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xNH0NCnJnbDo6Y2xlYXIzZCgpDQplbG1hdCAlPiUNCiAgc3BoZXJlX3NoYWRlKCkgJT4lDQogIGFkZF9vdmVybGF5KG92ZXJsYXlfaW1nLCBhbHBoYWxheWVyID0gMC45NSkgJT4lDQogIGFkZF9zaGFkb3cocmF5X3NoYWRvdywgbWF4X2Rhcmtlbj0wLjUpICU+JQ0KICBhZGRfc2hhZG93KGxhbWJfc2hhZG93LCBtYXhfZGFya2VuPTAuNSkgJT4lDQogIHBsb3RfM2QoZWxtYXQsIHpzY2FsZSA9IDUsd2luZG93c2l6ZSA9IGMoMTQwMCwxMDAwKSwgDQogICAgICAgICAgdGhldGEgPSAtNSwgcGhpID0gMzgsIHpvb20gPSAwLjUyLCBmb3YgPSA2MCwNCiAgICAgICAgICBiYWNrZ3JvdW5kID0gImdyZXk0MCIsIHNoYWRvd2NvbG9yID0gImdyZXkxMCIsIA0KICAgICAgICAgIHNvbGlkZGVwdGggPSAyMDAsIHNoYWRvd2RlcHRoID0gMTAwKQ0KU3lzLnNsZWVwKDUpDQpyZW5kZXJfc25hcHNob3QodGl0bGVfdGV4dCA9ICJDaG9uZ2xpIEFscGluZSBTa2kgUmVzb3J0IGluIFpoYW5namlha291IFxuMjAyMiBCZWlqaW5nIFdpbnRlciBPbHltcGljIiwNCiAgICAgICAgICAgICAgICB0aXRsZV9zaXplID0gNTAsIHRpdGxlX2NvbG9yID0gImdyZXk5MCIpDQpgYGANCg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTV9DQp6ID0gMTMwMDANCg0KZm9yKGkgaW4gMTpsZW5ndGgocG9pbnRzMV9sYWJlbCkpew0KICBsYWJlbCA8LSBsaXN0KHRleHQ9cG9pbnRzMV9sYWJlbFtpXSkNCiAgbGFiZWwkcG9zIDwtIGZpbmRfaW1hZ2VfY29vcmRpbmF0ZXMobG9uZz1wb2ludHMxJGxvbltpXSwgbGF0PXBvaW50czEkbGF0W2ldLCBiYm94PWJib3gsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWFnZV93aWR0aD1kaW0oZWxtYXQpWzFdLCBpbWFnZV9oZWlnaHQ9ZGltKGVsbWF0KVsyXSkNCiAgcmVuZGVyX2xhYmVsKGVsbWF0LCB4ID0gbGFiZWwkcG9zJHgsIHkgPSBsYWJlbCRwb3MkeSwgeiA9IHosDQogICAgICAgICAgICAgICB6c2NhbGUgPSB6c2NhbGUsIHRleHQgPSBsYWJlbCR0ZXh0LCB0ZXh0c2l6ZT0yLCBsaW5ld2lkdGggPSA0LCB0ZXh0Y29sb3I9Im1hZ2VudGEiLCBmcmVldHlwZT1GQUxTRSkNCn0NCg0KZm9yKGkgaW4gMTpsZW5ndGgocG9pbnRzMl9sYWJlbCkpew0KICBsYWJlbCA8LSBsaXN0KHRleHQ9cG9pbnRzMl9sYWJlbFtpXSkNCiAgbGFiZWwkcG9zIDwtIGZpbmRfaW1hZ2VfY29vcmRpbmF0ZXMobG9uZz1wb2ludHMyJGxvbltpXSwgbGF0PXBvaW50czIkbGF0W2ldLCBiYm94PWJib3gsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWFnZV93aWR0aD1kaW0oZWxtYXQpWzFdLCBpbWFnZV9oZWlnaHQ9ZGltKGVsbWF0KVsyXSkNCiAgcmVuZGVyX2xhYmVsKGVsbWF0LCB4ID0gbGFiZWwkcG9zJHgsIHkgPSBsYWJlbCRwb3MkeSwgeiA9IHosDQogICAgICAgICAgICAgICB6c2NhbGUgPSB6c2NhbGUsIHRleHQgPSBsYWJlbCR0ZXh0LCB0ZXh0c2l6ZT0yLCBsaW5ld2lkdGggPSA0LCB0ZXh0Y29sb3I9ImN5YW4iLCBmcmVldHlwZT1GQUxTRSkNCn0NCg0KZm9yKGkgaW4gMTpsZW5ndGgocG9pbnRzM19sYWJlbCkpew0KICBsYWJlbCA8LSBsaXN0KHRleHQ9cG9pbnRzM19sYWJlbFtpXSkNCiAgbGFiZWwkcG9zIDwtIGZpbmRfaW1hZ2VfY29vcmRpbmF0ZXMobG9uZz1wb2ludHMzJGxvbltpXSwgbGF0PXBvaW50czMkbGF0W2ldLCBiYm94PWJib3gsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWFnZV93aWR0aD1kaW0oZWxtYXQpWzFdLCBpbWFnZV9oZWlnaHQ9ZGltKGVsbWF0KVsyXSkNCiAgcmVuZGVyX2xhYmVsKGVsbWF0LCB4ID0gbGFiZWwkcG9zJHgsIHkgPSBsYWJlbCRwb3MkeSwgeiA9IHosDQogICAgICAgICAgICAgICB6c2NhbGUgPSB6c2NhbGUsIHRleHQgPSBsYWJlbCR0ZXh0LCB0ZXh0c2l6ZT0yLCBsaW5ld2lkdGggPSA0LCB0ZXh0Y29sb3I9InllbGxvdyIsIGZyZWV0eXBlPUZBTFNFKQ0KfQ0KDQpmb3IoaSBpbiAxOmxlbmd0aChwb2ludHM0X2xhYmVsKSl7DQogIGxhYmVsIDwtIGxpc3QodGV4dD1wb2ludHM0X2xhYmVsW2ldKQ0KICBsYWJlbCRwb3MgPC0gZmluZF9pbWFnZV9jb29yZGluYXRlcyhsb25nPXBvaW50czQkbG9uW2ldLCBsYXQ9cG9pbnRzNCRsYXRbaV0sIGJib3g9YmJveCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltYWdlX3dpZHRoPWRpbShlbG1hdClbMV0sIGltYWdlX2hlaWdodD1kaW0oZWxtYXQpWzJdKQ0KICByZW5kZXJfbGFiZWwoZWxtYXQsIHggPSBsYWJlbCRwb3MkeCwgeSA9IGxhYmVsJHBvcyR5LCB6ID0geiwNCiAgICAgICAgICAgICAgIHpzY2FsZSA9IHpzY2FsZSwgdGV4dCA9IGxhYmVsJHRleHQsIHRleHRzaXplPTIsIGxpbmV3aWR0aCA9IDQsIHRleHRjb2xvcj0iZ3JlZW4iLCBmcmVldHlwZT1GQUxTRSkNCn0NCg0KcmVuZGVyX3NuYXBzaG90KHRpdGxlX3RleHQgPSAiQ2hvbmdsaSBBbHBpbmUgU2tpIFJlc29ydCBpbiBaaGFuZ2ppYWtvdSBcbjIwMjIgQmVpamluZyBXaW50ZXIgT2x5bXBpYyIsDQogICAgICAgICAgICAgICAgdGl0bGVfc2l6ZSA9IDUwLCB0aXRsZV9jb2xvciA9ICJncmV5OTAiKQ0KYGBgDQoNCg0K